package com.hemerasolutions.v2trainer.component.search;


import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.annotation.PostConstruct;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;

import com.hemerasolutions.v2trainer.component.BaseComponent;
import com.hemerasolutions.v2trainer.component.interfaces.detail.TrainingSystemDetailsCompInterface;
import com.hemerasolutions.v2trainer.component.interfaces.list.StepListCompInterface;
import com.hemerasolutions.v2trainer.component.interfaces.search.ExerciseGroupSearchCompInterface;
import com.hemerasolutions.v2trainer.component.interfaces.search.ExerciseSearchCompInterface;
import com.hemerasolutions.v2trainer.component.interfaces.search.TrainingSystemSearchCompInterface;
import com.hemerasolutions.v2trainer.delegate.interfaces.ExerciseGroupSearchDelegateInterface;
import com.hemerasolutions.v2trainer.delegate.interfaces.ExerciseSearchDelegateInterface;
import com.hemerasolutions.v2trainer.delegate.interfaces.TrainingSystemSearchDelegateInterface;
import com.hemerasolutions.v2trainer.model.exercise.Exercise;
import com.hemerasolutions.v2trainer.model.exercise.TemplateExercise;
import com.hemerasolutions.v2trainer.model.exerciseGroup.ExerciseGroup;
import com.hemerasolutions.v2trainer.model.library.Library;
import com.hemerasolutions.v2trainer.model.modality.Modality;
import com.hemerasolutions.v2trainer.model.step.Step;
import com.hemerasolutions.v2trainer.model.training.Training;
import com.hemerasolutions.v2trainer.model.training.TrainingStep;
import com.hemerasolutions.v2trainer.model.training.TrainingType;
import com.hemerasolutions.v2trainer.service.interfaces.TrainingSystemServiceInterface;

@Component("trainingSystemSearchComp")
@Scope("prototype")
public class TrainingSystemSearchComp extends BaseComponent implements TrainingSystemSearchCompInterface, 
	ExerciseSearchDelegateInterface,ExerciseGroupSearchDelegateInterface {

	private static final long serialVersionUID = 1L;

	private Training trainingSystem;
	
	private Training selTrainingSystem;

	private TrainingSystemSearchDelegateInterface tsSearchDelegate;
	
	private List<TrainingType> findTrainingSystemByTrainingTypes;

	private List<Modality> findTrainingSystemByModalitys;
	
	private String trainingSystemFindByName;

	private String trainingSystemFindByDescription;

	private String trainingSystemFindByObs;

	private List<TrainingType> fullTrainingTypes;
	
	private List<Modality> fullModalitys;
	
	private Date trainingSystemBegCreatedAt;
	
	private Date trainingSystemEndCreatedAt;
	
	private Date trainingSystemBegChangedAt;
	
	private Date trainingSystemEndChangedAt;
	
	private boolean trainingSystemFindByStatus;
	
	private int importLevel;
	
	private List<Training> foundTrainingSystems;
	
	@Autowired
	private TrainingSystemDetailsCompInterface tsDetails;
	
	@Autowired
	private TrainingSystemServiceInterface tsService;

	@Autowired
	private StepListCompInterface stepListHandler;
	
	@Autowired
	private ExerciseGroupSearchCompInterface exerciseGroupSearchComp;
	
	@Autowired
	private ExerciseSearchCompInterface exerciseSearchComp;

	
	private List<TemplateExercise> templateExercises;
	
	private TemplateExercise selTemplate;
	
	
	@PostConstruct
	public void init(){
		super.init();
	}
	
	@Override
	public void refresh(){
		this.fullTrainingTypes = tsService.listTrainingTypes();
		this.trainingSystemFindByStatus = true;
		this.fullModalitys = new ArrayList<Modality>();
		
	}


	@Override
	public void addTrainingSystem(){
		this.tsSearchDelegate.onTrainingSystemAdd(this.selTrainingSystem);
	}
	
	
	@Override
	public void toViewTrainingSystem(){
		this.tsDetails.setTrainingSystem(this.trainingSystem);
		this.tsDetails.refresh();
	}
	
	@Override
	public void changeFullTrainingTypesAll(org.primefaces.event.ToggleSelectEvent ev){
		
		if(ev.isSelected()){
			this.findTrainingSystemByTrainingTypes = this.fullTrainingTypes;
		}else{
			this.findTrainingSystemByTrainingTypes = new ArrayList<TrainingType>();
		}
		
		this.changeFullTrainingTypes();
	}	
	

	@Override
	public void changeFullModalitysAll(org.primefaces.event.ToggleSelectEvent ev){
		
		if(ev.isSelected()){
			this.findTrainingSystemByModalitys = this.fullModalitys;
		}else{
			this.findTrainingSystemByModalitys = new ArrayList<Modality>();
		}
		
		this.changeFullTrainingTypes();
	}	
	
	
	@Override
	public void changeFullTrainingTypes(){
		this.fullModalitys = new ArrayList<Modality>();
		for(Library lib:this.getActiveUserAllowedLibrarys()){
			for(Modality mod:lib.getVersionableModalitys()){
				if(this.findTrainingSystemByTrainingTypes.contains(mod.getTrainingType())){
					this.fullModalitys.add(mod);
				}
			}
		}
	}
	
	@Override
	public void searchTrainingSystems(){

		Map<String,Object> fields = new HashMap<String, Object>();
    	
		if( this.trainingSystemBegCreatedAt != null && this.trainingSystemEndCreatedAt != null && 
				this.trainingSystemBegCreatedAt.compareTo(this.trainingSystemEndCreatedAt) > 0){
				this.showErrorMessage(	this.localizedText("CreationDate"),
										this.localizedText("TheInitialDateNeedToBeGreaterThanFinal"));
				return;
			}
			

		if( this.trainingSystemBegChangedAt != null && this.trainingSystemEndChangedAt != null && 
			this.trainingSystemBegChangedAt.compareTo(this.trainingSystemEndChangedAt) > 0){
			this.showErrorMessage(	this.localizedText("ChangeDate"),
									this.localizedText("TheInitialDateNeedToBeGreaterThanFinal"));
			return;			
		}
    	

    	if (!this.trainingSystemFindByName.equals("")) {
            fields.put("name", this.trainingSystemFindByName);
        }

    	if (!this.trainingSystemFindByDescription.equals("")) {
            fields.put("description", this.trainingSystemFindByDescription);
        }
    	
    	if (!this.trainingSystemFindByObs.equals("")){
    		fields.put("obs",this.trainingSystemFindByObs);
    	}

    	
    	if(this.findTrainingSystemByTrainingTypes != null && !this.findTrainingSystemByTrainingTypes.isEmpty() ){
    		fields.put("trainingTypes",this.findTrainingSystemByTrainingTypes);
    	}
    	
    	if(this.findTrainingSystemByModalitys != null && !this.findTrainingSystemByModalitys.isEmpty() ){
    		fields.put("modalitys",this.findTrainingSystemByModalitys);
    	}

    	fields.put("trainingSystem", true);
    	
    	fields.put("status", this.trainingSystemFindByStatus);
    	
	    this.foundTrainingSystems = this.tsService.searchTrainingSystems(fields);

		if((this.foundTrainingSystems).isEmpty()){
			this.showInfoMessage(	this.localizedText("SearchCompleted"),
									this.localizedText("NoEntrysFounded"));
		}else{
			this.showInfoMessage(	this.localizedText("SearchCompleted"),
									this.foundTrainingSystems.size() + " " + 
									this.localizedText("entrysFounded"));
		}
	    
		this.tsSearchDelegate.onSearchComplete(this.foundTrainingSystems);
		
	}

	
	
	@Override	
	public void toConfigTrainingSystem(){
		List<TemplateExercise> templates = new ArrayList<TemplateExercise>();
		
		this.templateExercises = new ArrayList<TemplateExercise>();	
		
		for(TrainingStep tss: trainingSystem.getTrainingSteps() ){
			if(tss.getLevel() == this.importLevel){

				templates.addAll(this.getRecursiveTemplate(tss.getRootStep().getSteps()));
				
				this.templateExercises = this.condenseTemplates(templates);
				
				this.stepListHandler.setStepLevel(tss);
				this.stepListHandler.refresh();
				
				break;
			}
		}		
		
	
	}
	
	@Override	
	public void toConfigTemplate(){
		this.exerciseGroupSearchComp.setExerciseGroupSearchDelegate(this);
		this.exerciseGroupSearchComp.refresh();
		
		this.exerciseSearchComp.setExerciseSearchDelegate(this);
		this.exerciseSearchComp.refresh();
		
	}

	
	
	private List<TemplateExercise> condenseTemplates(List<TemplateExercise> templates) {
		List<TemplateExercise> templatesAux = new ArrayList<TemplateExercise>();

		boolean founded = false;
		
		for(TemplateExercise template:templates){
			founded = false;
			for(TemplateExercise templateAux:templatesAux){
				if( template.getModality().equals(templateAux.getModality()) &&
					template.getVariation() == templateAux.getVariation()){
					founded = true;
				}
			}

			if(founded == false){
				templatesAux.add(template);
			}
		
		}
		
		return templatesAux;
	
	}

	private List<TemplateExercise> getRecursiveTemplate(List<Step> steps) {
		List<TemplateExercise> templates = new ArrayList<TemplateExercise>();

		for(Step step:steps){
			if(step.getType() == Step.EXERCISE_TEMPLATE){
				templates.add(step.getTemplateExercise());
			}
			
			if(step.getSteps() != null && !step.getSteps().isEmpty()){
				templates.addAll(this.getRecursiveTemplate(step.getSteps()));
			}
		}

		
		return templates;
	}

	
	private void replaceTemplateByGroup(ExerciseGroup exerciseGroup) {
		
		for(TrainingStep tss : this.trainingSystem.getTrainingSteps()){
			if(tss.getLevel() == this.importLevel){
				tss.getRootStep().setSteps(this.recursiveReplaceByExerciseGroup(tss.getRootStep().getSteps(),exerciseGroup));
				this.stepListHandler.refresh();

			}
		}
				
	}
	
	private void replaceTemplateByExercise(Exercise exercise) {

		for(TrainingStep tss : this.trainingSystem.getTrainingSteps()){
			if(tss.getLevel() == this.importLevel){
				tss.getRootStep().setSteps(this.recursiveReplaceByExercise(tss.getRootStep().getSteps(),exercise));
				this.stepListHandler.refresh();
			}
		}
		
	}	
	
	
	private List<Step> recursiveReplaceByExerciseGroup(List<Step> steps,ExerciseGroup exerciseGroup) {
		
		for(Step step: steps){
			if(step.getType() == Step.EXERCISE_TEMPLATE){
				if( step.getTemplateExercise().getModality().equals(this.selTemplate.getModality()) &&
					step.getTemplateExercise().getVariation() == this.selTemplate.getVariation()){

					step.convertTemplateToGroup(exerciseGroup);
				}
			}else{
				if(step.getSteps() != null && !step.getSteps().isEmpty()){
					this.recursiveReplaceByExerciseGroup(step.getSteps(), exerciseGroup);
				}
			}
		}
		
		return steps;
	}


	private List<Step> recursiveReplaceByExercise(List<Step> steps,Exercise exercise) {
		
		for(Step step: steps){
			if(step.getType() == Step.EXERCISE_TEMPLATE){
				if( step.getTemplateExercise().getModality().equals(this.selTemplate.getModality()) &&
					step.getTemplateExercise().getVariation() == this.selTemplate.getVariation()){

					step.convertTemplateToExercise(exercise);
				}
			}else{
				if(step.getSteps() != null && !step.getSteps().isEmpty()){
					this.recursiveReplaceByExercise(step.getSteps(), exercise);
				}
			}
		}
		
		return steps;
	}

	
	@Override
	public void transferSteps(){
		for(TrainingStep tss:this.trainingSystem.getTrainingSteps()){
			if(tss.getLevel() == this.importLevel){
				this.tsSearchDelegate.onTrainingSystemImportSteps(tss.getRootStep().getSteps());
			}
		}
	}

	
	
	
	@Override
	public Training getTrainingSystem() {
		return trainingSystem;
	}

	@Override
	public void setTrainingSystem(Training trainingSystem) {
		this.trainingSystem = trainingSystem;
	}

	@Override
	public Training getSelTrainingSystem() {
		return selTrainingSystem;
	}

	@Override
	public void setSelTrainingSystem(Training selTrainingSystem) {
		this.selTrainingSystem = selTrainingSystem;
	}

	@Override
	public TrainingSystemSearchDelegateInterface getTsSearchDelegate() {
		return tsSearchDelegate;
	}

	@Override
	public void setTsSearchDelegate(
			TrainingSystemSearchDelegateInterface tsSearchDelegate) {
		this.tsSearchDelegate = tsSearchDelegate;
	}

	@Override
	public List<TrainingType> getFindTrainingSystemByTrainingTypes() {
		return findTrainingSystemByTrainingTypes;
	}

	@Override
	public void setFindTrainingSystemByTrainingTypes(
			List<TrainingType> findTrainingSystemByTrainingTypes) {
		this.findTrainingSystemByTrainingTypes = findTrainingSystemByTrainingTypes;
	}

	@Override
	public List<Modality> getFindTrainingSystemByModalitys() {
		return findTrainingSystemByModalitys;
	}

	@Override
	public void setFindTrainingSystemByModalitys(
			List<Modality> findTrainingSystemByModalitys) {
		this.findTrainingSystemByModalitys = findTrainingSystemByModalitys;
	}

	@Override
	public String getTrainingSystemFindByName() {
		return trainingSystemFindByName;
	}

	@Override
	public void setTrainingSystemFindByName(String trainingSystemFindByName) {
		this.trainingSystemFindByName = trainingSystemFindByName;
	}

	@Override
	public String getTrainingSystemFindByDescription() {
		return trainingSystemFindByDescription;
	}

	@Override
	public void setTrainingSystemFindByDescription(
			String trainingSystemFindByDescription) {
		this.trainingSystemFindByDescription = trainingSystemFindByDescription;
	}

	@Override
	public String getTrainingSystemFindByObs() {
		return trainingSystemFindByObs;
	}

	@Override
	public void setTrainingSystemFindByObs(String trainingSystemFindByObs) {
		this.trainingSystemFindByObs = trainingSystemFindByObs;
	}

	@Override
	public List<TrainingType> getFullTrainingTypes() {
		return fullTrainingTypes;
	}

	@Override
	public void setFullTrainingTypes(List<TrainingType> fullTrainingTypes) {
		this.fullTrainingTypes = fullTrainingTypes;
	}

	@Override
	public List<Modality> getFullModalitys() {
		return fullModalitys;
	}

	@Override
	public void setFullModalitys(List<Modality> fullModalitys) {
		this.fullModalitys = fullModalitys;
	}

	@Override
	public Date getTrainingSystemBegCreatedAt() {
		return trainingSystemBegCreatedAt;
	}

	@Override
	public void setTrainingSystemBegCreatedAt(Date trainingSystemBegCreatedAt) {
		this.trainingSystemBegCreatedAt = trainingSystemBegCreatedAt;
	}

	@Override
	public Date getTrainingSystemEndCreatedAt() {
		return trainingSystemEndCreatedAt;
	}

	@Override
	public void setTrainingSystemEndCreatedAt(Date trainingSystemEndCreatedAt) {
		this.trainingSystemEndCreatedAt = trainingSystemEndCreatedAt;
	}

	@Override
	public Date getTrainingSystemBegChangedAt() {
		return trainingSystemBegChangedAt;
	}

	@Override
	public void setTrainingSystemBegChangedAt(Date trainingSystemBegChangedAt) {
		this.trainingSystemBegChangedAt = trainingSystemBegChangedAt;
	}

	@Override
	public Date getTrainingSystemEndChangedAt() {
		return trainingSystemEndChangedAt;
	}

	@Override
	public void setTrainingSystemEndChangedAt(Date trainingSystemEndChangedAt) {
		this.trainingSystemEndChangedAt = trainingSystemEndChangedAt;
	}

	@Override
	public boolean isTrainingSystemFindByStatus() {
		return trainingSystemFindByStatus;
	}

	@Override
	public void setTrainingSystemFindByStatus(boolean trainingSystemFindByStatus) {
		this.trainingSystemFindByStatus = trainingSystemFindByStatus;
	}

	@Override
	public List<Training> getFoundTrainingSystems() {
		return foundTrainingSystems;
	}

	@Override
	public void setFoundTrainingSystems(List<Training> foundTrainingSystems) {
		this.foundTrainingSystems = foundTrainingSystems;
	}

	@Override
	public TrainingSystemDetailsCompInterface getTsDetails() {
		return tsDetails;
	}

	@Override
	public void setTsDetails(TrainingSystemDetailsCompInterface tsDetails) {
		this.tsDetails = tsDetails;
	}

	@Override
	public boolean onExerciseGroupAdd(ExerciseGroup exerciseGroup) {
		this.replaceTemplateByGroup(exerciseGroup);
		
		return false;
	}


	@Override
	public boolean onExerciseAdd(Exercise exercise) {
		this.replaceTemplateByExercise(exercise);
		
		return false;
	}

	@Override
	public int getImportLevel() {
		return importLevel;
	}

	@Override
	public void setImportLevel(int importLevel) {
		this.importLevel = importLevel;
	}

	@Override
	public List<TemplateExercise> getTemplateExercises() {
		return templateExercises;
	}

	@Override
	public void setTemplateExercises(List<TemplateExercise> templateExercises) {
		this.templateExercises = templateExercises;
	}

	@Override
	public TemplateExercise getSelTemplate() {
		return selTemplate;
	}

	@Override
	public void setSelTemplate(TemplateExercise selTemplate) {
		this.selTemplate = selTemplate;
	}

	@Override
	public StepListCompInterface getStepListHandler() {
		return stepListHandler;
	}

	@Override
	public void setStepListHandler(StepListCompInterface stepListHandler) {
		this.stepListHandler = stepListHandler;
	}

	@Override
	public ExerciseGroupSearchCompInterface getExerciseGroupSearchComp() {
		return exerciseGroupSearchComp;
	}

	@Override
	public void setExerciseGroupSearchComp(
			ExerciseGroupSearchCompInterface exerciseGroupSearchComp) {
		this.exerciseGroupSearchComp = exerciseGroupSearchComp;
	}

	@Override
	public ExerciseSearchCompInterface getExerciseSearchComp() {
		return exerciseSearchComp;
	}

	@Override
	public void setExerciseSearchComp(ExerciseSearchCompInterface exerciseSearchComp) {
		this.exerciseSearchComp = exerciseSearchComp;
	}


	



}
